package org.dhbw.cocktail.mixer.internal;

import java.util.List;

import javax.persistence.EntityManager;
import javax.persistence.PersistenceContext;
import javax.persistence.Query;

import lombok.Data;

import org.dhbw.cocktail.Cocktail;
import org.dhbw.cocktail.CocktailType;
import org.dhbw.cocktail.Ingredient;
import org.springframework.transaction.annotation.Transactional;

/**
 * Data Access Object for the Cocktailmixer. Provides Methods to search, save,
 * retrieve cocktails/ingredients/cocktail-types in the Persistence-Unit
 * 
 * @author Roland von Werden
 * @version 0.1.2
 */
@Data
public class CocktailDAO {

	@PersistenceContext(unitName = "cocktailmixer")
	EntityManager em;

	/**
	 * Retrieve all cocktails from the Persistence-Unit
	 * 
	 * @return List with all cocktails
	 */
	@Transactional
	public List<Cocktail> getCocktails() {
		return em.createNamedQuery("all_cocktails", Cocktail.class).getResultList();
	}

	/**
	 * Retrieve all Ingredients from the Persistence-Unit
	 * 
	 * @return List with all ingredients
	 */
	@Transactional
	public List<Ingredient> getIngredients() {
		return em.createNamedQuery("all_ingredients", Ingredient.class).getResultList();
	}

	/**
	 * Retrieve all cocktails-types from the Persistence-Unit
	 * 
	 * @return List with all cocktails-types
	 */
	@Transactional
	public List<CocktailType> getCocktailTypes() {
		return em.createNamedQuery("all_types", CocktailType.class).getResultList();
	}

	/**
	 * Persist an existing cocktail(Update) or a new One(save)
	 * 
	 * @return returns whether the cocktail could be saved or not
	 */
	@Transactional
	public boolean saveCocktail(Cocktail cocktail) {
		try {
			if (cocktail.getId() == 0)
				em.persist(cocktail);
			else
				em.merge(cocktail);
			em.flush();
		} catch (Exception e) {
			e.printStackTrace();
			return false;
		}
		return true;
	}

	/**
	 * Persist an existing ingredient(update) or a new One(save)
	 * 
	 * @return returns whether the ingredient was saved or not
	 */
	@Transactional
	public boolean saveIngredient(Ingredient ingredient) {
		try {
			if (ingredient.getId() == 0)
				em.persist(ingredient);
			else
				em.merge(ingredient);
			em.flush();
		} catch (Exception e) {
			e.printStackTrace();
			return false;
		}
		return true;
	}

	/**
	 * Persist an existing cocktail-type(update) or persist a new One(save)
	 * 
	 * @return returns whether the cocktail-type was saved or not
	 */
	@Transactional(readOnly = false)
	public boolean saveCocktailType(CocktailType type) {
		try {
			if (type.getId() == 0)
				em.persist(type);
			else
				em.merge(type);
			em.flush();
		} catch (Exception e) {
			e.printStackTrace();
			return false;
		}
		return true;
	}

	/**
	 * Search for a cocktail in the Database
	 * 
	 * @return returns a list of cocktails, that matches the searched term
	 */
	@Transactional
	@SuppressWarnings("unchecked")
	public List<Cocktail> searchCocktail(String searchTerm) {
		Query q = em.createNamedQuery("search_cocktail", Cocktail.class);
		q.setParameter("searchTerm", "%" + searchTerm.toUpperCase() + "%");
		List<Cocktail> res = q.getResultList();
		return res;
	}

	/**
	 * Retrieve all cocktails from the Persistence-Unit by a specific Ingredient
	 * 
	 * @return List with all cocktails
	 */
	@Transactional
	@SuppressWarnings("unchecked")
	public List<Cocktail> getCocktailsByIngredientId(long id) {
		Query q = em.createNamedQuery("search_cocktails_by_ingredient_id", Cocktail.class);
		q.setParameter("ingredient_id", id);
		List<Cocktail> res = q.getResultList();
		return res;
	}

	/**
	 * Search for a cocktail in the Database
	 * 
	 * @return returns a cocktail that has the specified id, or NULL if there is
	 *         no match
	 */
	@Transactional
	public Cocktail getCocktailById(long id) {
		Query q = em.createNamedQuery("search_cocktail_by_id", Cocktail.class);
		q.setParameter("searchTerm", id);
		Cocktail res = (Cocktail) q.getSingleResult();
		return res;
	}

	/**
	 * Search for a ingredient in the Database
	 * 
	 * @return returns a list of ingredients, that matches the searched term
	 */
	@Transactional
	@SuppressWarnings("unchecked")
	public List<Ingredient> searchIngredient(String searchTerm) {
		Query q = em.createNamedQuery("search_ingredient", Ingredient.class);
		q.setParameter("searchTerm", "%" + searchTerm.toUpperCase() + "%");
		List<Ingredient> res = q.getResultList();
		return res;
	}

	/**
	 * Search for an ingredient in the Database
	 * 
	 * @return returns an ingredient that has the specified id, or NULL if there
	 *         is no match
	 */
	@Transactional
	public Ingredient getIngredientById(long id) {
		Query q = em.createNamedQuery("search_ingredient_by_id", Ingredient.class);
		q.setParameter("searchTerm", id);
		Ingredient res = (Ingredient) q.getSingleResult();
		return res;
	}

	/**
	 * Search for a cocktail-type in the Database
	 * 
	 * @return returns a list of cocktail-types, that matches the searched term
	 */
	@Transactional
	@SuppressWarnings("unchecked")
	public List<CocktailType> searchCocktailType(String searchTerm) {
		Query q = em.createNamedQuery("search_type", CocktailType.class);
		q.setParameter("searchTerm", "%" + searchTerm.toUpperCase() + "%");
		List<CocktailType> res = q.getResultList();
		return res;
	}

	/**
	 * Search for a cocktail-type in the Database
	 * 
	 * @return returns a cocktail-type that has the specified id, or NULL if
	 *         there is no match
	 */
	@Transactional
	public CocktailType getCocktailTypeById(long id) {
		Query q = em.createNamedQuery("search_type_by_id", CocktailType.class);
		q.setParameter("searchTerm", id);
		CocktailType res = (CocktailType) q.getSingleResult();
		return res;
	}
}
